package com.hevs.samplewebapp.server.service;

import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import com.google.appengine.api.datastore.Key;
import com.hevs.samplewebapp.server.dao.DAOFactory;
import com.hevs.samplewebapp.server.entities.User;
import com.hevs.samplewebapp.server.util.MD5Encoder;

/**
 * Service for user managment
 * 
 * @author Arnaud Durand
 * @date 14.03.12
 */
public class UserService extends Service {

	/**
	 * Default constructor
	 */
	public UserService() {
		super();
	}

	/**
	 * Constructor with specified DAOFactory
	 * 
	 * @param daoFactoryInstance
	 *            factory which is called for DAO instantiation
	 */
	public UserService(DAOFactory daoFactoryInstance) {
		super(daoFactoryInstance);
	}
	
	/**
	 * Get all users
	 * 
	 * @return list of users
	 */
	public List<User> getAllUsers() {
		return getUserDAO().getAll();
	}

	/**
	 * Get a complete user from his identifier
	 * 
	 * @param key identifier
	 * @return user
	 */
	public User getUser(Key key) {
		return getUserDAO().getUser(key);
	}

	/**
	 * Get a complete user from his unique login
	 * 
	 * @param login user login
	 * @return
	 */
	public User getUserByLogin(String login) {
		return getUserDAO().getUserByLogin(login);
	}

	/**
	 * Get a complete user from his unique email
	 * 
	 * @param mail user email
	 * @return user
	 */
	public User getUserByMail(String mail) {
		return getUserDAO().getUserByMail(mail);
	}

	/**
	 * Update a user or create a new one with a generated password
	 * 
	 * @param user
	 *            the user to be updated or created
	 */
	public void updateUser(User user) {

		if (user.getKey() != null) {
			// Update an existing user
			getUserDAO().update(user);
		} else {
			// Create a new user
			resetPassword(user);
			getUserDAO().update(user);
		}
	}

	/**
	 * Remove a user
	 * 
	 * @param user
	 *            the user to be removed
	 */
	public void removeUser(User user) {
		getUserDAO().remove(user);
	}

	/**
	 * Get the list of granted users for the specified user
	 * 
	 * @param local
	 *            target user
	 * @return list of granted users
	 */
	public List<User> getGrantedUsers(User local) {
		return getUserDAO().getGrantedUsers(local);
	}

	/**
	 * Grant acces to medical data of a local user to a remote user
	 * 
	 * @param local
	 *            the user who grant the access
	 * @param remote
	 *            the user that can access local user data
	 */
	public void grantAccess(User local, User remote) {
		getUserDAO().grantAccess(local, remote);
	}

	/**
	 * Revoke acces to medical data of a local user to a remote user
	 * 
	 * @param local
	 *            the user who revoke the access
	 * @param remote
	 *            the user that cannot access anymore local user data
	 */
	public void revokeAccess(User local, User remote) {
		getUserDAO().revokeAccess(local, remote);
	}

	/**
	 * Reset the specified user password and send him an email with his new
	 * password The user is persisted
	 * 
	 * @param user
	 */
	public void setNewPassword(User user) {
		resetPassword(user);
		getUserDAO().update(user);
	}

	/**
	 * Reset the specified user password and send him an email with his new
	 * password The user is not persisted
	 * 
	 * @param user
	 *            User on which the password will be reset
	 */
	private void resetPassword(User user) {
		String password = generatePassword();

		try {
			Properties props = new Properties();
			Session session = Session.getDefaultInstance(props, null);
			Message msg = new MimeMessage(session);
			String msgBody = "Your account password has been reset.\n------\nYour new password is: "
					+ password + ".";
			msg.setFrom(new InternetAddress("netbot32@gmail.com",
					"eHealth Admin"));
			msg.setSubject("Your eHealth password has been reset");
			msg.setText(msgBody);
			sendEmail(user, msg);
			user.setPassword(MD5Encoder.encode(password));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		}

	}

	/**
	 * Send an email to the specified user
	 * 
	 * @param user
	 *            the user that will receive the email
	 * @param message
	 *            message to send
	 */
	public void sendEmail(User user, Message message) {

		try {
			message.addRecipient(Message.RecipientType.TO,
					new InternetAddress(user.getEmail(), user.getFirstName()
							+ " " + user.getLastName()));
			Transport.send(message);

		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		} catch (MessagingException e1) {
			e1.printStackTrace();
		}

	}

	/**
	 * Length of the generated password
	 */
	public static final int PASSLENGTH_POLICY = 10;

	/**
	 * Input characters for generation
	 */
	private static char[] passChar = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
			'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
			'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M',
			'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2',
			'3', '4', '5', '6', '7', '8', '9' };

	/**
	 * Generates a random password
	 * 
	 * @return generatedPassword
	 */
	private static String generatePassword() {
		java.util.Random r = new java.util.Random();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < PASSLENGTH_POLICY; i++) {
			sb.append(passChar[r.nextInt(passChar.length)]);
		}
		return sb.toString();
	}

	

}
